home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / CW GUSI 1.6.4 / src / GUSIPAP.cp < prev    next >
Text File  |  1995-11-05  |  16KB  |  824 lines

  1. /*********************************************************************
  2. Project    :    GUSI                -    Grand Unified Socket Interface
  3. File        :    GUSIPAP.cp        -    Printer Access Protocol Sockets
  4. Author    :    Matthias Neeracher
  5.  
  6.     Based on code from 
  7.         Sak Wathanasin <sw@nan.co.uk>
  8.         David A. Holzgang, _Programming the LaserWriter_, Addison-Wesley 1991
  9.         Apple's Q&A stack
  10.     
  11. Language    :    MPW C/C++
  12.  
  13. $Log: GUSIPAP.cp,v $
  14. Revision 1.4  1994/12/30  20:13:59  neeri
  15. New file name dispatch scheme.
  16.  
  17. Revision 1.3  1994/08/10  00:06:51  neeri
  18. Sanitized for universal headers.
  19.  
  20. Revision 1.2  1994/05/01  23:30:32  neeri
  21. Enable recvfrom with non-NULL from address.
  22.  
  23. Revision 1.1  1994/02/25  02:29:50  neeri
  24. Initial revision
  25.  
  26. Revision 0.4  1993/12/30  00:00:00  neeri
  27. Fiddle with select
  28.  
  29. Revision 0.3  1993/09/01  00:00:00  neeri
  30. Throw out nonbreaking spaces
  31.  
  32. Revision 0.2  1993/04/03  00:00:00  neeri
  33. close() has to do shutdown as well.
  34.  
  35. Revision 0.1  1993/03/01  00:00:00  neeri
  36. Be more clever about handling shutdowns
  37.  
  38. *********************************************************************/
  39.  
  40. #include "GUSIFile_P.h"
  41.  
  42. #include <Resources.h>
  43. #include <AppleTalk.h>
  44. #include <Errors.h>
  45. #include <Folders.h>
  46. #include <PLStringFuncs.h>
  47. #include <TextUtils.h>
  48. #include <Timer.h>
  49.  
  50. #include <sys/types.h>
  51.  
  52. #if GENERATING68K
  53. #pragma segment GUSIPAP
  54. #endif
  55.  
  56. const long NiceDoggie    =    20;        // Rest Hellhound for 20msec
  57. const long MaxPAP            =    4096;        //    Maximum transaction size
  58.  
  59. class PAPSocket;                             // That's what this file's all about
  60.  
  61. class PAPID {
  62.     void        GetPAPCode(short vRefNum, long dirID, StringPtr name);
  63.     
  64.     Handle    papCode;
  65.     Handle    papName;    
  66. public:
  67.     PAPID();
  68.     
  69.     ~PAPID();
  70.     
  71.     Ptr    Code()            {    return *papCode;    }
  72.     Ptr    Name()            {    return *papName;    }
  73.     operator void *()        {    return papCode;    }
  74. };
  75.  
  76. struct PAPPB {
  77.     TMTask            timer;
  78.     short                length;
  79.     short                eof;
  80.     short                state;
  81.     PAPSocket *        sock;
  82. };
  83.  
  84. struct PAPStatusRec { 
  85.     long      systemStuff;
  86.    char      statusstr[256];
  87. };
  88.         
  89. class PAPSocket : public Socket    {        
  90.     friend class PAPSocketDomain;    
  91. #if !GENERATINGCFM
  92.     friend pascal void PAPReadTimer();
  93.     friend pascal void PAPWriteTimer();
  94. #endif
  95.     friend pascal void PAPReadHellHound(PAPPB *);
  96.     friend pascal void PAPWriteHellHound(PAPPB *);
  97.  
  98.     enum {
  99.         opening,
  100.         open,
  101.         closed
  102.     }                        status;
  103.     Boolean                nonblocking;
  104.     Boolean                readPending;
  105.     Boolean                writePending;
  106.     Boolean                readShutDown;
  107.     Boolean                writeShutDown;
  108.     short                    papRefNum;
  109.     RingBuffer *        rb;
  110.     RingBuffer *        wb;
  111.     long                    ourA5;
  112.     PAPID                    papID;
  113.     PAPStatusRec        papStatus;
  114.     PAPPB                    wpb;
  115.     PAPPB                    rpb;
  116.     
  117.                     PAPSocket();
  118.                     
  119.     virtual         ~PAPSocket();
  120.     
  121.     int            Powerup();
  122. public:
  123.     virtual int    fcntl(unsigned int cmd, int arg);
  124.     virtual int    recvfrom(void * buffer, int buflen, int flags, void * from, int *);
  125.     virtual int sendto(void * buffer, int buflen, int flags, void * to, int);
  126.     virtual int select(Boolean * canRead, Boolean * canWrite, Boolean * exception);
  127.     virtual int    ioctl(unsigned int request, void *argp);
  128.     virtual int shutdown(int how);
  129. };    
  130.  
  131. class PAPSocketDomain : public FileSocketDomain {
  132. public:
  133.     PAPSocketDomain()    :    FileSocketDomain(AF_PAP, true, false)    {    }
  134.     
  135.     virtual Boolean Yours(const GUSIFileRef & ref, Request request);
  136.     virtual Socket * open(const GUSIFileRef & ref, int oflag);
  137. };
  138.  
  139. PAPSocketDomain    PAPSockets;
  140.  
  141. /***************************** PAP glue *****************************/
  142.  
  143. #if !GENERATINGCFM
  144. pascal short PAPOpen(
  145.     short *             refNum, 
  146.     char *             printerName,
  147.     short             flowQuantum, 
  148.     PAPStatusRec * statusBuf, 
  149.     short *            compState,
  150.     Ptr                papCode
  151. )    =    {0x205F, 0x4EA8, 0x0000};
  152.  
  153. pascal short PAPRead(
  154.     short                refNum, 
  155.     char *            buffer,
  156.     short *            length, 
  157.     short *            eof,
  158.     short *            compState,
  159.     Ptr                papCode
  160. )    =    {0x205F, 0x4EA8, 0x0004};
  161.  
  162. pascal short PAPWrite(
  163.     short                 refNum,
  164.      char *            buffer,
  165.      short                length,
  166.      short                eof,
  167.      short *            compState,
  168.     Ptr                papCode
  169. )    =    {0x205F, 0x4EA8, 0x0008};
  170.  
  171. pascal short PAPStatus(
  172.     char    *            printerName,
  173.      PAPStatusRec *    statusBuff,
  174.      AddrBlock *        netAddr,
  175.     Ptr                papCode
  176. )    =    {0x205F, 0x4EA8, 0x000C};
  177.  
  178. pascal short PAPClose(
  179.      short                refNum,
  180.     Ptr                papCode
  181. )    =    {0x205F, 0x4EA8, 0x0010};
  182.  
  183. pascal short PAPUnload(
  184.     Ptr                papCode
  185. )    =    {0x205F, 0x4EA8, 0x0014};
  186. #else
  187. short PAPOpen(
  188.     short *             refNum, 
  189.     char *             printerName,
  190.     short             flowQuantum, 
  191.     PAPStatusRec * statusBuf, 
  192.     short *            compState,
  193.     Ptr                papCode
  194. ) {
  195.     return CallUniversalProc(
  196.         (UniversalProcPtr)(papCode + 0),
  197.         kPascalStackBased 
  198.             |    RESULT_SIZE(kTwoByteCode)
  199.             |    STACK_ROUTINE_PARAMETER(1, kFourByteCode)
  200.             |    STACK_ROUTINE_PARAMETER(2, kFourByteCode)
  201.             |    STACK_ROUTINE_PARAMETER(3, kTwoByteCode)
  202.             |    STACK_ROUTINE_PARAMETER(4, kFourByteCode)
  203.             |    STACK_ROUTINE_PARAMETER(5, kFourByteCode),
  204.         refNum, printerName, flowQuantum, statusBuf, compState);
  205. }
  206.  
  207. short PAPRead(
  208.     short                refNum, 
  209.     char *            buffer,
  210.     short *            length, 
  211.     short *            eof,
  212.     short *            compState,
  213.     Ptr                papCode
  214. ) {
  215.     return CallUniversalProc(
  216.         (UniversalProcPtr)(papCode + 4),
  217.         kPascalStackBased 
  218.             |    RESULT_SIZE(kTwoByteCode)
  219.             |    STACK_ROUTINE_PARAMETER(1, kTwoByteCode)
  220.             |    STACK_ROUTINE_PARAMETER(2, kFourByteCode)
  221.             |    STACK_ROUTINE_PARAMETER(3, kFourByteCode)
  222.             |    STACK_ROUTINE_PARAMETER(4, kFourByteCode)
  223.             |    STACK_ROUTINE_PARAMETER(5, kFourByteCode),
  224.         refNum, buffer, length, eof, compState);
  225. }
  226.  
  227. short PAPWrite(
  228.     short                 refNum,
  229.      char *            buffer,
  230.      short                length,
  231.      short                eof,
  232.      short *            compState,
  233.     Ptr                papCode
  234. ) {
  235.     return CallUniversalProc(
  236.         (UniversalProcPtr)(papCode + 8),
  237.         kPascalStackBased 
  238.             |    RESULT_SIZE(kTwoByteCode)
  239.             |    STACK_ROUTINE_PARAMETER(1, kTwoByteCode)
  240.             |    STACK_ROUTINE_PARAMETER(2, kFourByteCode)
  241.             |    STACK_ROUTINE_PARAMETER(3, kTwoByteCode)
  242.             |    STACK_ROUTINE_PARAMETER(4, kTwoByteCode)
  243.             |    STACK_ROUTINE_PARAMETER(5, kFourByteCode),
  244.         refNum, buffer, length, eof, compState);
  245. }
  246.  
  247. short PAPStatus(
  248.     char    *            printerName,
  249.      PAPStatusRec *    statusBuff,
  250.      AddrBlock *        netAddr,
  251.     Ptr                papCode
  252. ) {
  253.     return CallUniversalProc(
  254.         (UniversalProcPtr)(papCode + 12),
  255.         kPascalStackBased 
  256.             |    RESULT_SIZE(kTwoByteCode)
  257.             |    STACK_ROUTINE_PARAMETER(1, kFourByteCode)
  258.             |    STACK_ROUTINE_PARAMETER(2, kFourByteCode)
  259.             |    STACK_ROUTINE_PARAMETER(3, kFourByteCode),
  260.         printerName, statusBuff, netAddr);
  261. }
  262.  
  263. short PAPClose(
  264.      short                refNum,
  265.     Ptr                papCode
  266. )    {
  267.     return CallUniversalProc(
  268.         (UniversalProcPtr)(papCode + 16),
  269.         kPascalStackBased 
  270.             |    RESULT_SIZE(kTwoByteCode)
  271.             |    STACK_ROUTINE_PARAMETER(1, kTwoByteCode),
  272.         refNum);
  273. }
  274.  
  275. short PAPUnload(
  276.     Ptr                papCode
  277. )    {
  278.     return CallUniversalProc(
  279.         (UniversalProcPtr)(papCode + 20),
  280.         kPascalStackBased 
  281.             |    RESULT_SIZE(kTwoByteCode));
  282. }
  283. #endif
  284.  
  285. /********************* Link stuffing procedures *********************/
  286.  
  287. #if !GENERATINGCFM
  288. #ifdef __MWERKS__
  289. PAPPB * GetPAPInfo() : __D0 = 0x2009;                    // MOVE.L A1,D0
  290. #else
  291. PAPPB * GetPAPInfo() = 0x2009;                    // MOVE.L A1,D0
  292. #endif
  293.  
  294. pascal void PAPReadTimer()
  295. {
  296.     PAPPB *    pb        =    GetPAPInfo();
  297.     long        oldA5    =    SetA5(pb->sock->ourA5);
  298.     
  299.     PAPReadHellHound(pb);
  300.     
  301.     SetA5(oldA5);
  302. }
  303.  
  304. pascal void PAPWriteTimer()
  305. {
  306.     PAPPB *    pb        =    GetPAPInfo();
  307.     long        oldA5    =    SetA5(pb->sock->ourA5);
  308.     
  309.     PAPWriteHellHound(pb);
  310.     
  311.     SetA5(oldA5);
  312. }
  313.  
  314. #define uPAPReadTimer    PAPReadTimer
  315. #define uPAPWriteTimer    PAPWriteTimer
  316. #endif
  317.  
  318. pascal void PAPReadHellHound(PAPPB * pb)
  319. {
  320.     if (pb->state > 0) {
  321.         PrimeTime(QElemPtr(pb), NiceDoggie);        // See you again 
  322.         
  323.         return;
  324.     }
  325.     
  326.     if (!pb->sock->rb)                                    // We're closing
  327.         return;
  328.     
  329.     PAPSocket &        sock    =    *pb->sock;    
  330.     RingBuffer &     buf     =    *sock.rb;
  331.     Boolean &        pend    =    sock.readPending;
  332.         
  333.     if (buf.Locked())
  334.         buf.Later(Deferred(PAPReadHellHound), pb);
  335.     else    {
  336.         buf.Later(nil, nil);
  337.         if (pend) {
  338.             pend    =    false;
  339.             
  340.             if (pb->state)    {
  341.                 pb->sock->readShutDown    =    true;
  342.                 
  343.                 return;
  344.             }
  345.             
  346.             buf.Validate(pb->length);
  347.             
  348.             if (pb->eof){
  349.                 pb->sock->readShutDown    =    true;
  350.                 
  351.                 return;
  352.             }
  353.         }
  354.         
  355.         if (!buf.Free()) 
  356.             buf.Later(Deferred(PAPReadHellHound), pb);
  357.         else {
  358.             char *    buffer;
  359.             long        max    =    MaxPAP;
  360.             
  361.             buffer            =    buf.Producer(max);
  362.             pb->length        =    short(max);
  363.             pend                =    true;
  364.             
  365.             PAPRead(
  366.                 sock.papRefNum,
  367.                 buffer, 
  368.                 &pb->length,
  369.                 &pb->eof,
  370.                 &pb->state,
  371.                 sock.papID.Code());
  372.                 
  373.             PrimeTime(QElemPtr(pb), NiceDoggie);        // See you again 
  374.         }
  375.     }
  376.  
  377. }
  378.  
  379. pascal void PAPWriteHellHound(PAPPB * pb)
  380. {
  381.     if (pb->state > 0) {
  382.         PrimeTime(QElemPtr(pb), NiceDoggie);        // See you again 
  383.         
  384.         return;
  385.     }
  386.     
  387.     if (!pb->sock->wb)                                    // We're closing
  388.         return;
  389.         
  390.     PAPSocket &        sock    =    *pb->sock;    
  391.     RingBuffer &    buf     =    *sock.wb;
  392.     Boolean &        pend    =    sock.writePending;
  393.         
  394.     if (buf.Locked())
  395.         buf.Later(Deferred(PAPWriteHellHound), pb);
  396.     else    {
  397.         buf.Later(nil, nil);
  398.         
  399.         if (pend) {
  400.             if (pb->state)    {
  401.                 pb->sock->writeShutDown    =    true;
  402.                 pb->eof                        =    1;
  403.                 
  404.                 return;
  405.             }
  406.  
  407.             buf.Invalidate(pb->length);
  408.             pend    =    false;
  409.         }
  410.         
  411.         if (!buf.Valid()) {
  412.             if (pb->sock->writeShutDown && !pb->eof)
  413.                 PAPWrite(
  414.                     sock.papRefNum,
  415.                      0,
  416.                      0,
  417.                      pb->eof = 1,
  418.                      &pb->state,
  419.                     sock.papID.Code());
  420.             else
  421.                 buf.Later(Deferred(PAPWriteHellHound), pb);
  422.         } else {
  423.             char *     buffer;
  424.             long        max    =    MaxPAP;
  425.             
  426.             buffer            =    buf.Consumer(max);
  427.             pb->length        =    short(max);
  428.             pend                =    true;
  429.             
  430.             PAPWrite(
  431.                 sock.papRefNum,
  432.                  buffer,
  433.                  pb->length,
  434.                  0,
  435.                  &pb->state,
  436.                 sock.papID.Code());
  437.                 
  438.             PrimeTime(QElemPtr(pb), NiceDoggie);        // See you again
  439.         }
  440.     }
  441. }
  442.  
  443. #if GENERATINGCFM
  444. RoutineDescriptor    uPAPReadTimer =
  445.         BUILD_ROUTINE_DESCRIPTOR(uppTimerProcInfo, PAPReadHellHound);    
  446. RoutineDescriptor    uPAPWriteTimer =
  447.         BUILD_ROUTINE_DESCRIPTOR(uppTimerProcInfo, PAPWriteHellHound);    
  448. #endif
  449.  
  450. /************************** PAPID members **************************/
  451.  
  452. void PAPID::GetPAPCode(short vRefNum, long dirID, StringPtr name)
  453. {
  454.     short        res;
  455.     
  456.     res = HOpenResFile(vRefNum, dirID, name, fsRdPerm);
  457.     
  458.     if (res == -1)
  459.         return;
  460.         
  461.     papCode = Get1Resource('PDEF', 10);
  462.     
  463.     if (papCode) {
  464.         DetachResource(papCode);
  465.         MoveHHi(papCode);
  466.         HLock(papCode);
  467.     } else 
  468.         goto done;
  469.  
  470.     papName = Get1Resource('PAPA', -8192);
  471.     
  472.     if (papName) {
  473.         DetachResource(papName);
  474.         MoveHHi(papName);
  475.         HLock(papName);
  476.     } else {
  477.         DisposeHandle(papCode);
  478.         
  479.         papCode = nil;
  480.     }
  481.  
  482. done:    
  483.     CloseResFile(res);
  484. }
  485.  
  486. PAPID::PAPID()
  487. {
  488.     OSErr                err;
  489.     short                saveRes;
  490.     short                prVol;
  491.     long                prDir;
  492.     StringHandle    printer;
  493.         
  494.     papCode    =    nil;
  495.     papName    =    nil;
  496.  
  497.     if (err = FindFolder(
  498.                     kOnSystemDisk, 
  499.                     kExtensionFolderType, 
  500.                     kDontCreateFolder,
  501.                     &prVol,
  502.                     &prDir)
  503.     )
  504.         return;
  505.         
  506.     saveRes = CurResFile();
  507.     UseResFile(0);
  508.             
  509.     if (printer = StringHandle(Get1Resource('STR ', -8192))) {
  510.         HLock(Handle(printer));
  511.         
  512.         GetPAPCode(prVol, prDir, *printer);
  513.         
  514.         ReleaseResource(Handle(printer));
  515.     } 
  516.  
  517.     if (!papCode)
  518.         GetPAPCode(prVol, prDir, (StringPtr) "\pLaserWriter");
  519.     
  520.     UseResFile(saveRes);
  521. }
  522.  
  523. PAPID::~PAPID()
  524. {
  525.     if (papName)    
  526.         DisposeHandle(papName);
  527.     if (papCode)
  528.         DisposeHandle(papCode);
  529. }
  530.  
  531. /************************ PAPSocket members ************************/
  532.  
  533. PAPSocket::PAPSocket()
  534. {
  535.     status            =    PAPSocket::opening;
  536.     nonblocking        =    false;
  537.     rb                    =    new RingBuffer(4096);
  538.     wb                    =    new RingBuffer(4096);
  539.     readPending        =    false;
  540.     writePending    =    false;
  541.     readShutDown    =    false;
  542.     writeShutDown    =    false;
  543.     ourA5                =    SetCurrentA5();
  544.     
  545.     if (!papID) {
  546.         GUSI_error(ENETDOWN);
  547.         
  548.         return;
  549.     } else if (!rb || !wb) {
  550.         GUSI_error(ENOMEM);
  551.         
  552.         return;
  553.     }
  554.     
  555.     if (PAPOpen(&papRefNum, papID.Name(), 8, &papStatus, &wpb.state, papID.Code()))
  556.         GUSI_error(ENETDOWN);
  557. }
  558.  
  559. PAPSocket::~PAPSocket()
  560. {
  561.     char dummy;
  562.     
  563.     shutdown(1);                                                // Got nothing more to say
  564.     while (recvfrom(&dummy, 1, 0, nil, nil) > 0)        // Wait for printer to complete
  565.         ;
  566.         
  567.     PAPUnload(papID.Code());
  568.  
  569.     if (rb)
  570.         delete rb;
  571.     
  572.     if (wb)
  573.         delete wb;
  574. }
  575.  
  576. int PAPSocket::Powerup()
  577. {
  578.     switch (status) {
  579.     case PAPSocket::opening:
  580.         if (wpb.state > 0 && nonblocking)
  581.             return GUSI_error(EWOULDBLOCK);
  582.             
  583.         SPIN(wpb.state > 0, SP_MISC, 0);
  584.         
  585.         if (wpb.state) {
  586.             status = PAPSocket::closed;
  587.             
  588.             return GUSI_error(ENETDOWN);
  589.         } 
  590.         
  591.         status    =    PAPSocket::open;
  592.                 
  593.         rpb.timer.tmAddr        =    TimerUPP(&uPAPReadTimer);
  594.         rpb.timer.tmCount        =    0;
  595.         rpb.timer.tmWakeUp    =    0;
  596.         rpb.timer.tmReserved    =    0;
  597.         rpb.state            =  0;
  598.         rpb.sock                    =    this;
  599.         
  600.         wpb.timer.tmAddr        =    TimerUPP(&uPAPWriteTimer);
  601.         wpb.timer.tmCount        =    0;
  602.         wpb.timer.tmWakeUp    =    0;
  603.         wpb.timer.tmReserved    =    0;
  604.         wpb.sock                    =    this;
  605.         wpb.eof                    =    0;
  606.         
  607.         InsTime((QElem *) &rpb.timer);
  608.         InsTime((QElem *) &wpb.timer);
  609.         
  610.         PAPReadHellHound(&rpb);
  611.         PAPWriteHellHound(&wpb);
  612.     
  613.         return 0;
  614.     case PAPSocket::open:
  615.         return 0;
  616.     case PAPSocket::closed:
  617.     default:
  618.         return GUSI_error(ENOTCONN);
  619.     }
  620. }
  621.  
  622. int PAPSocket::fcntl(unsigned int cmd, int arg)
  623. {
  624.     switch (cmd)    {
  625.     case F_GETFL:
  626.         if (nonblocking)
  627.             return FNDELAY;
  628.         else
  629.             return 0;
  630.     case F_SETFL:
  631.         if (arg & FNDELAY)
  632.             nonblocking = true;
  633.         else
  634.             nonblocking = false;
  635.             
  636.         return 0;
  637.     default:
  638.         return GUSI_error(EOPNOTSUPP);
  639.     }
  640. }
  641.  
  642. int PAPSocket::ioctl(unsigned int request, void *argp)
  643. {
  644.     switch (request)    {
  645.     case FIONBIO:
  646.         nonblocking    =    (Boolean) *(long *) argp;
  647.         
  648.         return 0;
  649.     case FIONREAD:
  650.         if (Powerup())
  651.             return -1;
  652.             
  653.         if (status != PAPSocket::open)
  654.             return GUSI_error(ENOTCONN);    
  655.     
  656.         *(unsigned long *) argp    = rb->Valid();
  657.         
  658.         return 0;
  659.     default:
  660.         return GUSI_error(EOPNOTSUPP);
  661.     }
  662. }
  663.  
  664. int PAPSocket::recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen)
  665. {
  666.     /* This behaviour borders on the pathological, but this is what I currently
  667.        believe to be the least troublesome behaviour that is still correct.
  668.     */
  669.     if (from)
  670.         *fromlen = 0;
  671.     if (flags)
  672.         return GUSI_error(EOPNOTSUPP);
  673.  
  674.     if (Powerup())
  675.         return -1;
  676.         
  677.     if (!rb->Valid())    
  678.         if (readShutDown)
  679.             return 0;
  680.         else if (nonblocking)
  681.             return GUSI_error(EWOULDBLOCK);
  682.         else
  683.             SPIN(!rb->Valid() && !readShutDown, SP_STREAM_READ, 0);
  684.     
  685.     long    len    =    buflen;
  686.     
  687.     rb->Consume(Ptr(buffer), len);
  688.     
  689.     return len;
  690. }
  691.  
  692. int PAPSocket::sendto(void * buffer, int buflen, int flags, void * to, int)
  693. {
  694.     if (to)
  695.         return GUSI_error(EOPNOTSUPP);
  696.     if (flags)
  697.         return GUSI_error(EOPNOTSUPP);
  698.     
  699.     if (Powerup())
  700.         return -1;
  701.         
  702.     if (writeShutDown)
  703.         return GUSI_error(ESHUTDOWN);
  704.     
  705.     if (!wb->Free())
  706.         if (nonblocking)
  707.             return GUSI_error(EWOULDBLOCK);
  708.         
  709.     long    len    =    buflen;
  710.     long    done    =    0;
  711.     
  712.     for (;;) {
  713.         wb->Produce(Ptr(buffer), len);
  714.         
  715.         done        +=    len;
  716.         
  717.         if (nonblocking)
  718.             break;
  719.         
  720.         buflen    -=    int(len);
  721.         
  722.         if (!buflen)
  723.             break;
  724.         
  725.         buffer     =    Ptr(buffer) + len;
  726.         len        =    buflen;
  727.         
  728.         SPIN(!wb->Free() && !writeShutDown, SP_STREAM_WRITE, 0);
  729.         
  730.         if (writeShutDown)
  731.             break;
  732.     }
  733.     
  734.     return done;
  735. }
  736.  
  737. int PAPSocket::shutdown(int how)
  738. {
  739.     if (how < 0 || how > 2)
  740.         return GUSI_error(EINVAL);
  741.     
  742.     if (how) {
  743.         writeShutDown    =    true;
  744.         
  745.         if (status == PAPSocket::open)
  746.             wb->Undefer();                            //    Wake up write hellhound
  747.     }
  748.     if (!(how & 1))
  749.         readShutDown    =    true;
  750.         
  751.     return 0;
  752. }
  753.  
  754. int PAPSocket::select(Boolean * canRead, Boolean * canWrite, Boolean *)
  755. {
  756.     int        goodies     =     0;
  757.     
  758.     if (canRead)
  759.         switch (status) {
  760.         case PAPSocket::open:
  761.             if (rb->Valid() || readShutDown) {
  762.                 *canRead = true;
  763.                 ++goodies;
  764.             }
  765.             break;
  766.         case PAPSocket::opening:
  767.             break;
  768.         case PAPSocket::closed:
  769.             *canRead = true;
  770.             ++goodies;
  771.             break;
  772.         }
  773.     
  774.     if (canWrite)
  775.         switch (status) {
  776.         case PAPSocket::opening:
  777.             if (!(wpb.state > 0)) {
  778.                 *canWrite = true;
  779.                 ++goodies;
  780.             }
  781.             break;
  782.         case PAPSocket::open:
  783.             if (wb->Free() || writeShutDown) {
  784.                 *canWrite = true;
  785.                 ++goodies;
  786.             }
  787.             break;
  788.         case PAPSocket::closed:
  789.             *canRead = true;
  790.             ++goodies;
  791.             break;
  792.         }
  793.         
  794.     return goodies;
  795. }
  796.  
  797. /********************* PAPSocketDomain member **********************/
  798.  
  799. extern "C" void GUSIwithPAPSockets()
  800. {
  801.     PAPSockets.DontStrip();
  802. }
  803.  
  804. Boolean PAPSocketDomain::Yours(const GUSIFileRef & ref, FileSocketDomain::Request request)
  805. {
  806.     return !ref.spec && (request == willOpen || request == willStat) 
  807.         && equalstring((char *) ref.name, "dev:printer", false, true);
  808. }
  809.  
  810. Socket * PAPSocketDomain::open(const GUSIFileRef &, int)
  811. {
  812.     Socket *    sock;
  813.     
  814.     errno = 0;
  815.     sock     = new PAPSocket();
  816.     
  817.     if (sock && errno) {
  818.         delete sock;
  819.         
  820.         return nil;
  821.     } else
  822.         return sock;
  823. }
  824.